package com.lkd.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.google.common.collect.Lists;
import com.lkd.common.VMSystem;
import com.lkd.config.ConsulConfig;
import com.lkd.config.TopicConfig;
import com.lkd.contract.OrderCheck;
import com.lkd.contract.VendoutContract;
import com.lkd.contract.VendoutData;
import com.lkd.contract.VendoutResultContract;
import com.lkd.dao.OrderDao;
import com.lkd.emq.MqttProducer;
import com.lkd.entity.OrderEntity;
import com.lkd.exception.LogicException;
import com.lkd.feign.UserService;
import com.lkd.feign.VMService;
import com.lkd.mybatis.utils.DistributedLock;
import com.lkd.service.OrderService;
import com.lkd.vo.*;
import com.lkd.wxpay.WxPayDTO;
import com.lkd.wxpay.WxPaySDKUtil;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.BucketOrder;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {

    @Autowired
    private RestHighLevelClient esClient;

    @Autowired
    private VMService vmService;

    @Autowired
    private ConsulConfig consulConfig;

    @Autowired
    UserService userService;

    @Autowired
    private MqttProducer mqttProducer;


    @Override
    public OrderEntity getByOrderNo(String orderNo) {
        QueryWrapper<OrderEntity> qw = new QueryWrapper<>();
        qw.lambda()
                .eq(OrderEntity::getOrderNo, orderNo);
        return this.getOne(qw);
    }


    @Override
    public Pager<OrderVO> search(Integer pageIndex, Integer pageSize, String orderNo, String openId, String startDate, String endDate) {
        return Pager.buildEmpty();
    }


    @Override
    public List<Long> getTop10Sku(Integer businessId) {

        SearchRequest searchRequest = new SearchRequest("order");
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        //查询条件：最近三个月

        RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("update_time");
        rangeQueryBuilder.gte(LocalDateTime.now().plusMonths(-3).format(DateTimeFormatter.ISO_DATE_TIME));
        rangeQueryBuilder.lte(LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME));

        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(rangeQueryBuilder);

        boolQueryBuilder.must(QueryBuilders.termQuery("business_id", businessId));
        sourceBuilder.query(boolQueryBuilder);

        AggregationBuilder orderAgg = AggregationBuilders.terms("sku").field("sku_id")
                .subAggregation(AggregationBuilders.count("count").field("sku_id"))
                .order(BucketOrder.aggregation("count", false))
                .size(10);

        sourceBuilder.aggregation(orderAgg);
        searchRequest.source(sourceBuilder);

        try {
            SearchResponse searchResponse = esClient.search(searchRequest, RequestOptions.DEFAULT);
            Aggregations aggregations = searchResponse.getAggregations();
            if (aggregations == null) return Lists.newArrayList();

            var term = (Terms) aggregations.get("sku");
            var buckets = term.getBuckets();

            return buckets.stream().map(b -> Long.valueOf(b.getKey().toString())).collect(Collectors.toList());

        } catch (IOException e) {
            e.printStackTrace();
            return Lists.newArrayList();
        }

    }

    /**
     * 下单
     *
     * @param payVO
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public OrderEntity createOrder(PayVO payVO) {
        //1.创建订单
        OrderEntity order = new OrderEntity();
        //1.1 判断库存
        Boolean capacity = vmService.hasCapacity(payVO.getInnerCode(), Long.parseLong(payVO.getSkuId()));
        if (capacity == null || !capacity) {
            throw new LogicException("商品库存不足");
        }


        //1.2查询售货机相关信息
        VmVO vmInfo = vmService.getVMInfo(payVO.getInnerCode());
        BeanUtils.copyProperties(vmInfo, order);
        order.setAddr(vmInfo.getNodeAddr());

        //1.3查询商品相关的信息
        SkuVO sku = vmService.getSku(payVO.getSkuId());
        BeanUtils.copyProperties(sku, order);
        order.setStatus(VMSystem.ORDER_STATUS_CREATE);

        //1.4查询商品相关信息
        PartnerVO partner = userService.getPartner(vmInfo.getOwnerId());
        BeanUtils.copyProperties(partner, order);
        //1.5查询合作商信息,计算分成
        BigDecimal decimal = new BigDecimal(sku.getRealPrice());
        int bill = decimal.multiply(new BigDecimal(partner.getRatio())).divide(new BigDecimal(100), 0, RoundingMode.HALF_UP).intValue();
        //合作商分成
        order.setBill(bill);

        //设置基础信息
        //订单号
        order.setOrderNo(payVO.getInnerCode() + System.nanoTime());
        order.setPayType("2");
        order.setPayStatus(VMSystem.PAY_STATUS_NOPAY);
        order.setOpenId(payVO.getOpenId());

        //保存信息到order表
        this.save(order);


        return order;
    }

    /**
     * 微信下单
     *
     * @param payVO
     * @return
     */
    @Override
    public String weixinPay(PayVO payVO) {

        //创建订单
        OrderEntity orderEntity = createOrder(payVO);
        //2.发起支付请求
        WxPaySDKUtil wxPaySDKUtil = new WxPaySDKUtil();
        WxPayDTO wxPayDTO = new WxPayDTO();
        wxPayDTO.setOpenid(payVO.getOpenId());
        wxPayDTO.setBody(orderEntity.getSkuName());
        wxPayDTO.setTotalFee(orderEntity.getAmount());
        wxPayDTO.setOutTradeNo(orderEntity.getOrderNo());
        wxPayDTO.setExpireSecond(600);

        //发送延迟消息检查订单
        OrderCheck orderCheck = new OrderCheck();
        orderCheck.setOrderNo(orderCheck.getOrderNo());
        orderCheck.setInnerCode(payVO.getInnerCode());
        try {
            mqttProducer.send("$delayed/600/" + TopicConfig.ORDER_CHECK_TOPIC, 2, orderCheck);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return wxPaySDKUtil.requestPay(wxPayDTO);
    }

    /**
     * 微信支付成功回调通知出货
     *
     * @param orderId
     */
    @Override
    public void vendout(String orderId) {
        //1.查询订单
        OrderEntity orderEntity = getOne(Wrappers.<OrderEntity>lambdaQuery().eq(OrderEntity::getOrderNo,orderId));
        if (orderEntity == null) {
            return;
        }
        //2.修改支付状态
        orderEntity.setPayStatus(VMSystem.PAY_STATUS_PAYED);
        //3.修改订单状态
        orderEntity.setStatus(VMSystem.ORDER_STATUS_PAYED);

        updateById(orderEntity);

        //4.通知售货机修改库存
        //封装出货类
        VendoutContract vendoutContract = new VendoutContract();
        vendoutContract.setInnerCode(orderEntity.getInnerCode());
        VendoutData vendoutData = new VendoutData();
        vendoutData.setOrderNo(orderEntity.getOrderNo());
        vendoutData.setSkuId(orderEntity.getSkuId());
        //根据售货机编号和商品id查询货道编号并设置协议
        ChannelVo channel = vmService.getChannel(orderEntity.getInnerCode(), orderEntity.getSkuId());
        if (channel != null) {
            vendoutData.setChannelCode(channel.getChannelCode());
        }
        vendoutContract.setVendoutData(vendoutData);

        //发送消息到售货机微服务
        try {
            mqttProducer.send(TopicConfig.VMS_VENDOUT_TOPIC,2,vendoutContract);
        } catch (JsonProcessingException e) {
            log.error("出货消息发送失败" + e.getMessage());
        }
    }

    /**
     * 出货成功
     *
     * @param resultContract
     */
    @Override
    public void vendoutSuccess(VendoutResultContract resultContract) {
        updateOrderStatus(resultContract.getVendoutData().getOrderNo(),VMSystem.ORDER_STATUS_VENDOUT_SUCCESS);
    }

    /**
     * 出货失败
     *
     * @param resultContract
     */
    @Override
    public void vendoutFail(VendoutResultContract resultContract) {
        updateOrderStatus(resultContract.getVendoutData().getOrderNo(),VMSystem.ORDER_STATUS_VENDOUT_FAIL);
    }

    /**
     * 修改订单状态
     * @param orderNo
     * @param status
     */
    private void updateOrderStatus(String orderNo,Integer status) {
        //查询订单
        OrderEntity orderEntity = getOne(Wrappers.<OrderEntity>lambdaQuery()
                .eq(OrderEntity::getOrderNo, orderNo));
        //更改状态
        orderEntity.setStatus(status);
        this.updateById(orderEntity);
    }

}





















